/*
* compile codes for browser-side script
* use all things webpack can use, pack codes into one big file (or splitted chunk files)
* also used for webpack dev server, which do no outputs, just for hot module development
*/
import path from 'path'
import webpack from 'webpack'
import autoprefixer from 'autoprefixer'
import MiniCssExtractPlugin from 'mini-css-extract-plugin'
import HtmlWebpackPlugin from 'html-webpack-plugin'
import { CleanWebpackPlugin } from 'clean-webpack-plugin'
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'
import LoadablePlugin from '@loadable/webpack-plugin'

import PROJECT from './PROJECT'
import { ENV, ENVS } from './ENV'
import { FilesMapPlugin } from './webpack.plugin'

const BABEL_CONFIG = {
  presets: [
    require('@babel/preset-flow'),
    require('@babel/preset-react'),
    require('@babel/preset-env'),
  ],
  plugins: [
    require('@babel/plugin-syntax-dynamic-import'),
    require('@babel/plugin-transform-runtime'),
    require('@loadable/babel-plugin'),
    require('react-hot-loader/babel'),
  ]
}

const COMMON_MODULES = [
  'react', 'react-dom', 'react-hot-loader', 'react-router-dom', 
  'prop-types', 'axios', 'redux', 'redux-thunk', 'react-redux',
]

const relativeDist = path.relative(PROJECT.BUILD_CLIENT.ROOT, PROJECT.BUILD_CLIENT.DIST)
const relativeAssets = path.relative(PROJECT.BUILD_CLIENT.ROOT, PROJECT.BUILD_CLIENT.ASSETS)
const relativeHtml = path.relative(PROJECT.BUILD_CLIENT.ROOT, PROJECT.BUILD_CLIENT.HTML)
const relativeLoadable = path.relative(PROJECT.BUILD_CLIENT.ROOT, PROJECT.BUILD_CLIENT.MANIFEST_LOADABLE)
const relativeFilesmap = path.relative(PROJECT.BUILD_CLIENT.ROOT, PROJECT.BUILD_CLIENT.MANIFEST_FILESMAP)

const constants = () => {
  const config = {
    __ssr_isomorphic_tools__: JSON.stringify(false)
  }

  const env = Object.assign({}, ENV, {
    IS_CLIENT: true,
    HOST: null,
    PORT: null,
  })

  for (const key in env) {
    const value = env[key]
    config[`ENV.${key}`] = JSON.stringify(value)
  }

  return config
}

const cssPlugins = [
  autoprefixer({
    overrideBrowserslist: [
      '>1%',
      'last 4 versions',
      'Firefox ESR',
      'not ie < 9', // React doesn't support IE8 anyway
    ]
  }),
]

ENV.IS_MOBILE && cssPlugins.push(
  pxtorem({
    rootValue: 100,
    propWhiteList: []
  })
)

const webpackConfig = {
  context: __dirname,

  mode: (ENV.NAME === 'production' ? 'production' : 'development'),

  devtool: (ENV.NAME === 'production' ? 'cheap-source-map' : 'inline-source-map'),

  entry: {
    vendor: COMMON_MODULES,
    main: PROJECT.SRC.ENTRY,
  },

  output: {
    path: PROJECT.BUILD_CLIENT.ROOT,
    publicPath: ENV.PUBLIC,
    filename: `${relativeDist}/[name].[hash:8].js`,
    chunkFilename: `${relativeDist}/[name].[hash:8].js`,
  },

  optimization: {
    splitChunks: {
      cacheGroups: {
        vendor: {
          chunks: 'initial',
          name: 'vendor',
          test: 'vendor',
        }
      }
    }
  },

  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: ENV.MODE_TEST ? [/node_modules/, path.resolve(PROJECT.ROOT, '../build')] : /node_modules/,
        use: [{
          loader: 'babel-loader',
          options: BABEL_CONFIG,
        }]
      },
      {
        test: /\.less$/,
        use: [ 
          ENV.NAME === 'hot' ? 'style-loader' : MiniCssExtractPlugin.loader,
          'css-loader', 
          {
            loader: 'postcss-loader',
            options: {
              plugins: cssPlugins
            }
          },
          'less-loader' 
        ]
      },
      {
        test: /\.(png|jpg|gif)$/,
        use: [
          { 
            loader: 'file-loader',
            options: {
              name: `${relativeAssets}/[name].[hash:8].[ext]`,
            }
          }
        ]
      }
    ]
  },

  plugins: [
    new CleanWebpackPlugin(),

    new MiniCssExtractPlugin({
      // Options similar to the same options in webpackOptions.output
      // both options are optional
      filename: `${relativeDist}/[name].[hash:8].css`,
      chunkFilename: `${relativeDist}/[name].[hash:8].css`
    }),

    new HtmlWebpackPlugin({
      template: path.resolve(__dirname + '/index.html'),
      filename: relativeHtml,
      inject: ENV.MODE_SSR ? false : true,
      minify: ENV.NAME === 'production' ? true : false,
      config: ENVS.html || {},
    }),

    new webpack.HotModuleReplacementPlugin(),

    new webpack.DefinePlugin(constants()),

    new FilesMapPlugin({ filename: relativeFilesmap }),

    new LoadablePlugin({ filename: relativeLoadable, writeToDisk: true }),
  ]
}

ENV.NAME === 'hot' &&
ENV.IS_NEED_ANALYZER === true &&
webpackConfig.plugins.push(new BundleAnalyzerPlugin())

export default webpackConfig
